package com.diandi.code.service;

import com.diandi.code.util.FreemarkerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Created by 袁恩光 on 2018/5/7.
 */
@Service
public class CodeAutoService {

    private static final Logger logger = LoggerFactory.getLogger(CodeAutoService.class);

    /**
     * 项目名前缀
     */
    private static final String APPLICATION_NAME = "dd-";


    public ResponseEntity<byte[]> getResponseEntity(String modelName) throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", APPLICATION_NAME + modelName + ".zip");
        return new ResponseEntity<>(getZipStream(modelName).toByteArray(), headers, HttpStatus.CREATED);
    }

    /**
     * 创建zip
     */
    private ByteArrayOutputStream getZipStream(String modelName) throws Exception {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        ZipOutputStream outputStream = new ZipOutputStream(byteStream);
        //创建外层model
        outputStream = this.getOutTemplate(outputStream, modelName);
        //创建api层
        outputStream = getApiTemplate(outputStream, modelName);
        //创建batchRun层
        outputStream = getBachRunTemplate(outputStream, modelName);
        //创建DB层
        outputStream = getDbTemplate(outputStream, modelName);
        //创建service层
        outputStream = getServiceTemplate(outputStream, modelName);
        //创建util层
        outputStream = getUtilTemplate(outputStream, modelName);
        //创建web层
        outputStream = getWebTemplate(outputStream, modelName);
        byteStream.close();
        outputStream.closeEntry();
        outputStream.close();
        return byteStream;
    }


    /**
     * 生成外层 model
     *
     * @param modelName 项目名称
     * @return 生成好的 stream
     */
    private ZipOutputStream getOutTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建外层");
        //创建 readme.md
        outputStream.putNextEntry(new ZipEntry("README.md"));
        ByteArrayOutputStream stream = FreemarkerUtil.createStream("common/README.md", modelName);
        outputStream.write(stream.toByteArray());
        //创建外层.gitignore
        outputStream.putNextEntry(new ZipEntry(".gitignore"));
        ByteArrayOutputStream gitignore = FreemarkerUtil.createStream("common/.gitignore", new HashMap<>());
        outputStream.write(gitignore.toByteArray());
        //外层pom 创建
        outputStream.putNextEntry(new ZipEntry("pom.xml"));
        ByteArrayOutputStream wpom = FreemarkerUtil.createStream("common/pom.xml", modelName);
        outputStream.write(wpom.toByteArray());

        return outputStream;
    }


    /**
     * 创建api层
     *
     * @param outputStream zip 输出流
     * @param modelName    modelName
     */
    private ZipOutputStream getApiTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建api");
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-api/pom.xml"));
        ByteArrayOutputStream apiPom = FreemarkerUtil.createStream("api/pom.xml", modelName);
        outputStream.write(apiPom.toByteArray());
        //testapi
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-api/src/main/java/com/diandi/" + modelName + "/api/TtService.java"));
        ByteArrayOutputStream testService = FreemarkerUtil.createStream("api/TtService.java", modelName);
        outputStream.write(testService.toByteArray());
        //constant
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-api/src/main/java/com/diandi/Constant.java"));
        ByteArrayOutputStream contant = FreemarkerUtil.createStream("api/Constant.java", modelName);
        outputStream.write(contant.toByteArray());
        return outputStream;
    }

    /**
     * batchTemplate
     */
    private ZipOutputStream getBachRunTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建batchRun");

        //pom
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/pom.xml"));
        ByteArrayOutputStream apiPom = FreemarkerUtil.createStream("batchRun/pom.xml", modelName);
        outputStream.write(apiPom.toByteArray());
        //start.sh
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/start.sh"));
        ByteArrayOutputStream startsh = FreemarkerUtil.createStream("batchRun/start.sh", modelName);
        outputStream.write(startsh.toByteArray());
        //stop.sh
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/stop.sh"));
        ByteArrayOutputStream stopsh = FreemarkerUtil.createStream("batchRun/stop.sh", modelName);
        outputStream.write(stopsh.toByteArray());


        //logback-spring.xml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/src/main/resources/logback-spring.xml"));
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource resource = pathMatchingResourcePatternResolver.getResource("classpath:/template/batchRun/logback-spring.xml");
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
        String xml = FileCopyUtils.copyToString(encodedResource.getReader());
        xml = xml.replace("${modelName}", modelName);
        outputStream.write(xml.getBytes());


        //application.yml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/src/main/resources/application.yml"));
        ByteArrayOutputStream appli = FreemarkerUtil.createStream("batchRun/application.yml", modelName);
        outputStream.write(appli.toByteArray());

        //bootstrap.yml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/src/main/resources/bootstrap.yml"));
        ByteArrayOutputStream bootstrap = FreemarkerUtil.createStream("batchRun/bootstrap.yml", modelName);
        outputStream.write(bootstrap.toByteArray());


        //feignClien配置文件
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/src/main/java/com/diandi/" + modelName + "/config/FeignConfig.java"));
        ByteArrayOutputStream feign = FreemarkerUtil.createStream("batchRun/FeignConfig.java", modelName);
        outputStream.write(feign.toByteArray());

        //application 启动文件生成
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/src/main/java/com/diandi/" + modelName + "/Application.java"));
        ByteArrayOutputStream application = FreemarkerUtil.createStream("batchRun/Application.java", modelName);
        outputStream.write(application.toByteArray());


        //timerTest
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-batchRun/src/main/java/com/diandi/" + modelName + "/TimerTest.java"));
        ByteArrayOutputStream timetest = FreemarkerUtil.createStream("batchRun/TimerTest.java", modelName);
        outputStream.write(timetest.toByteArray());

        return outputStream;
    }


    /**
     * db生成
     */
    private ZipOutputStream getDbTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建db");

        //pom
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-db/pom.xml"));
        ByteArrayOutputStream apiPom = FreemarkerUtil.createStream("db/pom.xml", modelName);
        outputStream.write(apiPom.toByteArray());
        //baseEntity
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-db/src/main/java/com/diandi/" + modelName + "/bean/BaseEntity.java"));
        ByteArrayOutputStream testService = FreemarkerUtil.createStream("db/BaseEntity.java", modelName);
        outputStream.write(testService.toByteArray());

        //mapper
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-db/src/main/java/com/diandi/" + modelName + "/mapper/"));
        ByteArrayOutputStream mapper = new ByteArrayOutputStream();
        outputStream.write(mapper.toByteArray());

        //xml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-db/src/main/resources/" + modelName + "xmlMapper/"));
        ByteArrayOutputStream mapperxml = new ByteArrayOutputStream();
        outputStream.write(mapperxml.toByteArray());

        return outputStream;
    }


    /**
     * service 生成
     */
    private ZipOutputStream getServiceTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建service");

        //pom
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/pom.xml"));
        ByteArrayOutputStream apiPom = FreemarkerUtil.createStream("service/pom.xml", modelName);
        outputStream.write(apiPom.toByteArray());
        //start.sh
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/start.sh"));
        ByteArrayOutputStream startsh = FreemarkerUtil.createStream("service/start.sh", modelName);
        outputStream.write(startsh.toByteArray());
        //stop.sh
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/stop.sh"));
        ByteArrayOutputStream stopsh = FreemarkerUtil.createStream("service/stop.sh", modelName);
        outputStream.write(stopsh.toByteArray());
        //logback-spring.xml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/resources/logback-spring.xml"));
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource resource = pathMatchingResourcePatternResolver.getResource("classpath:/template/service/logback-spring.xml");
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
        String xml = FileCopyUtils.copyToString(encodedResource.getReader());
        xml = xml.replace("${modelName}", modelName);
        outputStream.write(xml.getBytes());


        //application.yml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/resources/application.yml"));
        ByteArrayOutputStream appli = FreemarkerUtil.createStream("service/application.yml", modelName);
        outputStream.write(appli.toByteArray());

        //bootstrap.yml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/resources/bootstrap.yml"));
        ByteArrayOutputStream bootstrap = FreemarkerUtil.createStream("service/bootstrap.yml", modelName);
        outputStream.write(bootstrap.toByteArray());

        //config
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/java/com/diandi/" + modelName + "/config/"));
        ByteArrayOutputStream config = new ByteArrayOutputStream();
        outputStream.write(config.toByteArray());

        //manager and impl
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/java/com/diandi/" + modelName + "/manager/"));
        ByteArrayOutputStream manager = new ByteArrayOutputStream();
        outputStream.write(manager.toByteArray());
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/java/com/diandi/" + modelName + "/manager/impl/"));
        ByteArrayOutputStream managerimpl = new ByteArrayOutputStream();
        outputStream.write(managerimpl.toByteArray());
        //api impl
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/java/com/diandi/" + modelName + "/api/impl/TtServiceImpl.java"));
        ByteArrayOutputStream apiimpl = FreemarkerUtil.createStream("service/TtServiceImpl.java", modelName);
        outputStream.write(apiimpl.toByteArray());

        //api impl
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-service/src/main/java/com/diandi/Application.java"));
        ByteArrayOutputStream application = FreemarkerUtil.createStream("service/Application.java", modelName);
        outputStream.write(application.toByteArray());

        return outputStream;
    }

    /**
     * util层
     */
    private ZipOutputStream getUtilTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建util");

        //pom
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-utils/pom.xml"));
        ByteArrayOutputStream utilPom = FreemarkerUtil.createStream("util/pom.xml", modelName);
        outputStream.write(utilPom.toByteArray());
        return outputStream;
    }


    /**
     * web
     */
    private ZipOutputStream getWebTemplate(ZipOutputStream outputStream, String modelName) throws Exception {
        logger.info("创建web");

        //pom
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/pom.xml"));
        ByteArrayOutputStream apiPom = FreemarkerUtil.createStream("web/pom.xml", modelName);
        outputStream.write(apiPom.toByteArray());
        //start.sh
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/start.sh"));
        ByteArrayOutputStream startsh = FreemarkerUtil.createStream("web/start.sh", modelName);
        outputStream.write(startsh.toByteArray());
        //stop.sh
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/stop.sh"));
        ByteArrayOutputStream stopsh = FreemarkerUtil.createStream("web/stop.sh", modelName);
        outputStream.write(stopsh.toByteArray());

        //logback-spring.xml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/resources/logback-spring.xml"));
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource resource = pathMatchingResourcePatternResolver.getResource("classpath:/template/web/logback-spring.xml");
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
        String xml = FileCopyUtils.copyToString(encodedResource.getReader());
        xml = xml.replace("${modelName}", modelName);
        outputStream.write(xml.getBytes());


        //application.yml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/resources/application.yml"));
        ByteArrayOutputStream appli = FreemarkerUtil.createStream("web/application.yml", modelName);
        outputStream.write(appli.toByteArray());

        //bootstrap.yml
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/resources/bootstrap.yml"));
        ByteArrayOutputStream bootstrap = FreemarkerUtil.createStream("web/bootstrap.yml", modelName);
        outputStream.write(bootstrap.toByteArray());


        //feignClien配置文件
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/java/com/diandi/" + modelName + "/config/FeignConfig.java"));
        ByteArrayOutputStream feign = FreemarkerUtil.createStream("web/FeignConfig.java", modelName);
        outputStream.write(feign.toByteArray());

        //application 启动文件生成
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/java/com/diandi/Application.java"));
        ByteArrayOutputStream application = FreemarkerUtil.createStream("web/Application.java", modelName);
        outputStream.write(application.toByteArray());


        //controller
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/java/com/diandi/" + modelName + "/controller/TestController.java"));
        ByteArrayOutputStream controller = FreemarkerUtil.createStream("web/TestController.java", modelName);
        outputStream.write(controller.toByteArray());

        //demo.ftl
        outputStream.putNextEntry(new ZipEntry("dd-" + modelName + "-web/src/main/resources/templates/demo.ftl"));
        ByteArrayOutputStream demo = FreemarkerUtil.createStream("web/demo.ftl", modelName);
        outputStream.write(demo.toByteArray());

        return outputStream;
    }


}
